#include "daemon.h"
#include <stdio.h>
#include <QDebug>
#include <string>
#include <QTime>

//#define PRINT_DEBUG_INFO

#ifdef PRINT_DEBUG_INFO
inline void info(const char *format, ...)
{
    FILE *file = fopen("C:/2.txt", "a");

    std::string nowTime = QTime::currentTime().toString(Qt::ISODate).toStdString();
    char buf[500];
    va_list vlist;
    va_start(vlist, format);
    vsprintf(buf, format, vlist);
    va_end(vlist);
    //    printf("INFO[%s]: %s\n", nowTime.c_str(), buf);
    fprintf(file, "INFO[%s]: %s\n", nowTime.c_str(), buf);
    fclose(file);
}

#else
#define info(...)
#endif


#define WAIT 0
#define QUERY 1
#define QUIT 2

struct pid_hwnd_pair {
    ULONG got_pid;
    RECT rect;
};


struct sharedMemoryData{
    ULONG pthreadId;
    ULONG left, right, top, bottom;
};

BOOL CALLBACK
SetWindowRect(HWND hwnd, LPARAM lParam){
    pid_hwnd_pair * p = (pid_hwnd_pair *)lParam;
    ULONG lpdwProcessId;
    GetWindowThreadProcessId(hwnd, &lpdwProcessId);
    if (p->got_pid == lpdwProcessId){
        RECT newRect;
        GetWindowRect(hwnd, &newRect);
        info("left = %d right = %d top = %d bottom = %d",
             newRect.left, newRect.right, newRect.top, newRect.bottom);
        if (newRect.top < p->rect.top) p->rect.top = newRect.top;
        if (newRect.left < p->rect.left) p->rect.left = newRect.left;
        if (newRect.bottom > p->rect.bottom) p->rect.bottom = newRect.bottom;
        if (newRect.right > p->rect.right) p->rect.right = newRect.right;
        info("After: left = %d right = %d top = %d bottom = %d",
             (int)p->rect.left, (int)p->rect.right, (int)p->rect.top, (int)p->rect.bottom);
    }
    return TRUE;
}

BOOL CALLBACK
EnumWindowsProcMy(HWND hwnd, LPARAM lParam)
{
    pid_hwnd_pair * p = (pid_hwnd_pair *)lParam;
    ULONG lpdwProcessId;
    GetWindowThreadProcessId(hwnd, &lpdwProcessId);
    if (p->got_pid == lpdwProcessId){
        if (IsIconic(hwnd)){
            ShowWindow(hwnd, SW_RESTORE);
        }
        RECT newRect;
        GetWindowRect(hwnd, &newRect);
        info("left = %d right = %d top = %d bottom = %d",
             (int)newRect.left, (int)newRect.right, (int)newRect.top, (int)newRect.bottom);
        if (newRect.top < p->rect.top) p->rect.top = newRect.top;
        if (newRect.left < p->rect.left) p->rect.left = newRect.left;
        if (newRect.bottom > p->rect.bottom) p->rect.bottom = newRect.bottom;
        if (newRect.right > p->rect.right) p->rect.right = newRect.right;
        info("After: left = %d right = %d top = %d bottom = %d",
             (int)p->rect.left, (int)p->rect.right, (int)p->rect.top, (int)p->rect.bottom);
    }
    EnumChildWindows(hwnd, SetWindowRect, lParam);
    return TRUE;
}

RECT Daemon::flush_and_get_rect(ULONG pid) {
    pid_hwnd_pair pair;
    pair.got_pid = pid;
    pair.rect.left = MAX_WIDTH;
    pair.rect.top = MAX_HEIGHT;
    pair.rect.right = pair.rect.bottom = 0;
    EnumWindows(EnumWindowsProcMy, (LPARAM)&pair);
    return pair.rect;
}

Daemon::Daemon(QString sharedMemoryName, int pthreadId, int w, int h)
{
    this->MAX_WIDTH = w;
    this->MAX_HEIGHT = h;
    this->pthreadId = pthreadId;
    info("program dwpid = %d", pthreadId);
    sharedMemory = new QSharedMemory();
    sharedMemory->setNativeKey(QString("Global\\") + sharedMemoryName);
    if (sharedMemory->isAttached())
        if (!sharedMemory->detach())
            info("Unable to detach from shared memory.");

    int size = 4096;
    if (!sharedMemory->create(size)){
        info("Unable to create shared memory");
    }

    std::string temp_sharedMemoryName = sharedMemoryName.toStdString();
    info("create memory succeeded: %s", temp_sharedMemoryName.c_str());

    connect(&timer, SIGNAL(timeout()), this, SLOT(readData()));
    timer.setInterval(500);
    timer.start();
}

void Daemon::readData(){
    RECT rect = flush_and_get_rect(pthreadId);
    sharedMemory->lock();
    char *to = (char *)sharedMemory->data();
    volatile sharedMemoryData *data = (sharedMemoryData *)to;
    info("---------------begin-----------------");
    if (rect.left <= 0) rect.left = 0;
    if (rect.top <= 0) rect.top = 0;
    if (rect.right > MAX_WIDTH) rect.right = MAX_WIDTH;
    if (rect.bottom > MAX_HEIGHT) rect.bottom = MAX_HEIGHT;
    data->left = rect.left;
    data->right = rect.right;
    data->top = rect.top;
    data->bottom = rect.bottom;
    info("end: left=%d right=%d top=%d bottom=%d", rect.left, rect.right, rect.top, rect.bottom);
    info("---------------end-----------------");
    sharedMemory->unlock();
}

Daemon::~Daemon(){
    delete sharedMemory;
}
